package com.demo.modules.stock.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.modules.stock.dao.StockDayDao;
import com.demo.modules.stock.entity.StockDayEntity;
import com.demo.modules.stock.entity.StockInfoEntity;
import com.demo.modules.stock.service.StockDayService;
import com.demo.modules.stock.service.StockInfoService;
import com.demo.modules.stock.util.StockUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;

@Service("stockDayService")
public class StockDayServiceImpl extends ServiceImpl<StockDayDao, StockDayEntity> implements StockDayService {

    @Autowired
    private StockInfoService stockInfoService;

    /**
     * 和数据库比对日期,若存在则更新,不存在则插入
     */
    @Override
    public void insertOrUpdateStockHistoryClosePrice(StockInfoEntity stockInfoEntity, List<List<String>> price) {

        List<StockDayEntity> addOrUpdateList = new ArrayList<>(2000);
        List<StockDayEntity> dbStock = this.baseMapper.selectList(new QueryWrapper<StockDayEntity>().select("ID,DAY_DATE")
                .eq("STOCK_CODE", stockInfoEntity.getStockCode()));

        StockDayEntity addOrUpdate;
        for (List<String> c : price) {
            Optional<StockDayEntity> optional = dbStock.stream().filter(item -> DateUtil.format(item.getDayDate(), "yyyy-MM-dd").equals(c.get(0))).findFirst();
            if (optional.isPresent()) {
                //更新股票价格
                addOrUpdate = new StockDayEntity();
                addOrUpdate.setId(optional.get().getId());
                addOrUpdate.setClosePrice(Double.valueOf(c.get(1)));
                addOrUpdate.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                addOrUpdateList.add(addOrUpdate);
            } else {
                //插入股票价格
                addOrUpdate = new StockDayEntity();
                addOrUpdate.setStockCode(stockInfoEntity.getStockCode());
                addOrUpdate.setStockName(stockInfoEntity.getStockName());
                addOrUpdate.setDayDate(DateUtil.parse(c.get(0)));
                addOrUpdate.setClosePrice(Double.valueOf(c.get(1)));
                addOrUpdate.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                addOrUpdateList.add(addOrUpdate);
            }
        }

        this.saveOrUpdateBatch(addOrUpdateList, 255);
    }

    @Override
    public void insertOrUpdateStockRealTimePrice(String stockDate, StockInfoEntity stock, String[] price) {
        StockDayEntity stockDayEntity = this.baseMapper.selectOne(new QueryWrapper<StockDayEntity>()
                .eq("STOCK_CODE", stock.getStockCode())
                .eq("DAY_DATE", stockDate));
        if (stockDayEntity == null) {
            stockDayEntity = new StockDayEntity();
        }
        stockDayEntity.setStockCode(stock.getStockCode());
        stockDayEntity.setStockName(stock.getStockName());
        stockDayEntity.setDayDate(DateUtil.parse(price[4], "yyyy-MM-dd"));
        stockDayEntity.setOpenPrice(Double.valueOf(price[0]));
        stockDayEntity.setClosePrice(Double.valueOf(price[1]));
        stockDayEntity.setHighest(Double.valueOf(price[2]));
        stockDayEntity.setLowest(Double.valueOf(price[3]));
        this.saveOrUpdate(stockDayEntity);
    }

    /**
     * 更新股票历史价格
     *
     * @param stockInfoEntity 股票信息
     * @param price           股票历史价格,依次是开盘价、收盘价、最高价、最低价
     */
    @Override
    public void insertOrUpdateStockHistoryAllPrice(StockInfoEntity stockInfoEntity, List<List<String>> price) {
        List<StockDayEntity> addOrUpdateList = new ArrayList<>(2000);
        log.debug("查询数据库中股票的所有历史价格");
        List<StockDayEntity> dbStock = this.baseMapper.selectList(new QueryWrapper<StockDayEntity>().select("ID,DAY_DATE")
                .eq("STOCK_CODE", stockInfoEntity.getStockCode()));

        StockDayEntity addOrUpdate;
        //遍历第三方接口获取股票的历史价格,根据日期查询是否存在于数据库中,存在则更新数据库的股票历史价格，不存在则插入
        for (List<String> c : price) {
            Optional<StockDayEntity> optional = dbStock.stream().filter(item -> DateUtil.format(item.getDayDate(), "yyyy-MM-dd").equals(c.get(0))).findFirst();
            if (optional.isPresent()) {
                //更新股票价格
                addOrUpdate = new StockDayEntity();
                addOrUpdate.setId(optional.get().getId());
                addOrUpdate.setOpenPrice(Double.valueOf(c.get(1)));
                addOrUpdate.setClosePrice(Double.valueOf(c.get(2)));
                addOrUpdate.setHighest(Double.valueOf(c.get(3)));
                addOrUpdate.setLowest(Double.valueOf(c.get(4)));
                addOrUpdate.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                addOrUpdateList.add(addOrUpdate);
            } else {
                //插入股票价格
                addOrUpdate = new StockDayEntity();
                addOrUpdate.setStockCode(stockInfoEntity.getStockCode());
                addOrUpdate.setStockName(stockInfoEntity.getStockName());
                addOrUpdate.setDayDate(DateUtil.parse(c.get(0)));
                addOrUpdate.setOpenPrice(Double.valueOf(c.get(1)));
                addOrUpdate.setClosePrice(Double.valueOf(c.get(2)));
                addOrUpdate.setHighest(Double.valueOf(c.get(3)));
                addOrUpdate.setLowest(Double.valueOf(c.get(4)));
                addOrUpdate.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                addOrUpdateList.add(addOrUpdate);
            }
        }

        this.saveOrUpdateBatch(addOrUpdateList, 1000);
    }

    /**
     * 根据股票code查询最小日期和最大日期,不在此范围内则插入
     */
    @Override
    public void insertStockHistoryClosePrice() {
        List<StockInfoEntity> stockInfoEntityList = stockInfoService.list();
        for (StockInfoEntity stock : stockInfoEntityList) {
            List<List<String>> close = StockUtils.getStockClosePriceByBaidu(stock.getStockCode());
            if (close == null) continue;
            log.debug("成功获取股票" + stock.getStockCode() + "收盘价格");

            List<StockDayEntity> stockDayEntityList = new ArrayList<>(2000);
            StockDayEntity dbMaxDateEntity = this.baseMapper.selectOne(new QueryWrapper<StockDayEntity>().select("max(day_date) as day_date").eq("STOCK_CODE", stock.getStockCode()));
            if (dbMaxDateEntity != null) {
                String dbMaxDate = DateUtil.format(dbMaxDateEntity.getDayDate(), "yyyy-MM-dd");
                for (List<String> c : close) {
                    if (c.get(0).compareTo(dbMaxDate) > 0) {
                        StockDayEntity dayEntity = new StockDayEntity();
                        dayEntity.setStockCode(stock.getStockCode());
                        dayEntity.setStockName(stock.getStockName());
                        dayEntity.setDayDate(DateUtil.parse(c.get(0)));
                        dayEntity.setClosePrice(Double.valueOf(c.get(1)));
                        dayEntity.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                        stockDayEntityList.add(dayEntity);
                    }
                }
            } else {
                for (List<String> c : close) {
                    StockDayEntity dayEntity = new StockDayEntity();
                    dayEntity.setStockCode(stock.getStockCode());
                    dayEntity.setStockName(stock.getStockName());
                    dayEntity.setDayDate(DateUtil.parse(c.get(0)));
                    dayEntity.setClosePrice(Double.valueOf(c.get(1)));
                    dayEntity.setCreateTime(new Timestamp(DateUtil.date().getTime()));
                    stockDayEntityList.add(dayEntity);
                }
            }

            this.saveBatch(stockDayEntityList, 255);
        }
    }

    @Override
    public List<StockDayEntity> getStockHistoryClosePrice(String stockCode) {
        return this.baseMapper.selectList(new QueryWrapper<StockDayEntity>()
                .select("id,day_date,open_price,close_price,lowest,highest,volume,net_change_ratio,stock_code,stock_name,create_time")
                .eq("stock_code", stockCode)
                .orderByAsc("DAY_DATE"));
    }

    /**
     * 获取股票的最新交易日期,选取固定股票代码浦发银行600000查询
     *
     * @return 最新交易日期,格式"2021-01-01"
     */
    @Override
    public String getRecentStockExchangeDate() {
        StockDayEntity stockDayEntity = this.baseMapper.selectOne(new QueryWrapper<StockDayEntity>().select("day_date").eq("STOCK_CODE", "600000").orderByDesc("DAY_DATE").last("limit 1"));
        return DateUtil.format(stockDayEntity.getDayDate(), DatePattern.NORM_DATE_PATTERN);
    }

    @Override
    public LinkedList<String> riseAndFall(int flag, Integer num) {
        List<StockDayEntity> tmp = this.list(new QueryWrapper<StockDayEntity>().select("day_date").eq("STOCK_CODE", "600000").orderByDesc("DAY_DATE"));

        Date startDate = tmp.get(num - 1).getDayDate();
        Date endDate = tmp.get(0).getDayDate();

        log.debug("获取最近几天的所有股票价格");
        List<StockDayEntity> stockDayEntityList = this.list(new QueryWrapper<StockDayEntity>()
                .select("id,day_date,open_price,close_price,lowest,highest,volume,net_change_ratio,stock_code,stock_name")
                .between("DAY_DATE", startDate, endDate).orderByDesc("STOCK_CODE").orderByAsc("DAY_DATE"));

        ArrayList<Double> tmpPrice = new ArrayList<>();
        String pCode = stockDayEntityList.get(0).getStockCode();
        LinkedList<String> stockCodes = new LinkedList<>();

        //拿到同一股票的按照日期递增排序的股票价格
        for (StockDayEntity e : stockDayEntityList) {
            if (!e.getStockCode().equals(pCode)) {
                if (isRiseOrFall(tmpPrice, flag)) {
                    stockCodes.add(pCode);
                }
                pCode = e.getStockCode();
                tmpPrice = new ArrayList<>();
            }
            tmpPrice.add(e.getClosePrice());
        }

        if (isRiseOrFall(tmpPrice, flag)) {
            stockCodes.add(pCode);
        }

        return stockCodes;
    }

    private boolean isRiseOrFall(ArrayList<Double> data, int flag) {
        if (data.size() < 2) return false;
        if (flag == 1) {
            for (int i = 1; i < data.size(); i++) {
                if (data.get(i) < data.get(i - 1)) return false;
            }
        }
        if (flag == 2) {
            for (int i = 1; i < data.size(); i++) {
                if (data.get(i) > data.get(i - 1)) return false;
            }
        }

        return true;
    }
}
